home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / share / gtk-2.0 / demo / hypertext.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-04-25  |  9.1 KB  |  319 lines

  1. /* Text Widget/Hypertext
  2.  *
  3.  * Usually, tags modify the appearance of text in the view, e.g. making it 
  4.  * bold or colored or underlined. But tags are not restricted to appearance. 
  5.  * They can also affect the behavior of mouse and key presses, as this demo 
  6.  * shows.
  7.  */
  8.  
  9. #include <gtk/gtk.h>
  10. #include <gdk/gdkkeysyms.h>
  11.  
  12. /* Inserts a piece of text into the buffer, giving it the usual
  13.  * appearance of a hyperlink in a web browser: blue and underlined.
  14.  * Additionally, attaches some data on the tag, to make it recognizable
  15.  * as a link. 
  16.  */
  17. static void 
  18. insert_link (GtkTextBuffer *buffer, 
  19.          GtkTextIter   *iter, 
  20.          gchar         *text, 
  21.          gint           page)
  22. {
  23.   GtkTextTag *tag;
  24.   
  25.   tag = gtk_text_buffer_create_tag (buffer, NULL, 
  26.                     "foreground", "blue", 
  27.                     "underline", PANGO_UNDERLINE_SINGLE, 
  28.                     NULL);
  29.   g_object_set_data (G_OBJECT (tag), "page", GINT_TO_POINTER (page));
  30.   gtk_text_buffer_insert_with_tags (buffer, iter, text, -1, tag, NULL);
  31. }
  32.  
  33. /* Fills the buffer with text and interspersed links. In any real
  34.  * hypertext app, this method would parse a file to identify the links.
  35.  */
  36. static void
  37. show_page (GtkTextBuffer *buffer, 
  38.        gint           page)
  39. {
  40.   GtkTextIter iter;
  41.  
  42.   gtk_text_buffer_set_text (buffer, "", 0);
  43.   gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
  44.   if (page == 1)
  45.     {
  46.       gtk_text_buffer_insert (buffer, &iter, "Some text to show that simple ", -1);
  47.       insert_link (buffer, &iter, "hypertext", 3);
  48.       gtk_text_buffer_insert (buffer, &iter, " can easily be realized with ", -1);
  49.       insert_link (buffer, &iter, "tags", 2);
  50.       gtk_text_buffer_insert (buffer, &iter, ".", -1);
  51.     }
  52.   else if (page == 2)
  53.     {
  54.       gtk_text_buffer_insert (buffer, &iter, 
  55.                   "A tag is an attribute that can be applied to some range of text. "
  56.                   "For example, a tag might be called \"bold\" and make the text inside "
  57.                   "the tag bold. However, the tag concept is more general than that; "
  58.                   "tags don't have to affect appearance. They can instead affect the "
  59.                   "behavior of mouse and key presses, \"lock\" a range of text so the "
  60.                   "user can't edit it, or countless other things.\n", -1);
  61.       insert_link (buffer, &iter, "Go back", 1);
  62.     }
  63.   else if (page == 3) 
  64.     {
  65.       GtkTextTag *tag;
  66.   
  67.       tag = gtk_text_buffer_create_tag (buffer, NULL, 
  68.                     "weight", PANGO_WEIGHT_BOLD, 
  69.                     NULL);
  70.       gtk_text_buffer_insert_with_tags (buffer, &iter, "hypertext:\n", -1, tag, NULL);
  71.       gtk_text_buffer_insert (buffer, &iter, 
  72.                   "machine-readable text that is not sequential but is organized "
  73.                   "so that related items of information are connected.\n", -1);
  74.       insert_link (buffer, &iter, "Go back", 1);
  75.     }
  76. }
  77.  
  78. /* Looks at all tags covering the position of iter in the text view, 
  79.  * and if one of them is a link, follow it by showing the page identified
  80.  * by the data attached to it.
  81.  */
  82. static void
  83. follow_if_link (GtkWidget   *text_view, 
  84.         GtkTextIter *iter)
  85. {
  86.   GSList *tags = NULL, *tagp = NULL;
  87.  
  88.   tags = gtk_text_iter_get_tags (iter);
  89.   for (tagp = tags;  tagp != NULL;  tagp = tagp->next)
  90.     {
  91.       GtkTextTag *tag = tagp->data;
  92.       gint page = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tag), "page"));
  93.  
  94.       if (page != 0)
  95.         {
  96.       show_page (gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)), page);
  97.       break;
  98.         }
  99.     }
  100.  
  101.   if (tags) 
  102.     g_slist_free (tags);
  103. }
  104.  
  105. /* Links can be activated by pressing Enter.
  106.  */
  107. static gboolean
  108. key_press_event (GtkWidget *text_view,
  109.          GdkEventKey *event)
  110. {
  111.   GtkTextIter iter;
  112.   GtkTextBuffer *buffer;
  113.  
  114.   switch (event->keyval)
  115.     {
  116.       case GDK_Return: 
  117.       case GDK_KP_Enter:
  118.         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
  119.         gtk_text_buffer_get_iter_at_mark (buffer, &iter, 
  120.                                           gtk_text_buffer_get_insert (buffer));
  121.         follow_if_link (text_view, &iter);
  122.         break;
  123.  
  124.       default:
  125.         break;
  126.     }
  127.  
  128.   return FALSE;
  129. }
  130.  
  131. /* Links can also be activated by clicking.
  132.  */
  133. static gboolean
  134. event_after (GtkWidget *text_view,
  135.          GdkEvent  *ev)
  136. {
  137.   GtkTextIter start, end, iter;
  138.   GtkTextBuffer *buffer;
  139.   GdkEventButton *event;
  140.   gint x, y;
  141.  
  142.   if (ev->type != GDK_BUTTON_RELEASE)
  143.     return FALSE;
  144.  
  145.   event = (GdkEventButton *)ev;
  146.  
  147.   if (event->button != 1)
  148.     return FALSE;
  149.  
  150.   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
  151.  
  152.   /* we shouldn't follow a link if the user has selected something */
  153.   gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
  154.   if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
  155.     return FALSE;
  156.  
  157.   gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), 
  158.                                          GTK_TEXT_WINDOW_WIDGET,
  159.                                          event->x, event->y, &x, &y);
  160.  
  161.   gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y);
  162.  
  163.   follow_if_link (text_view, &iter);
  164.  
  165.   return FALSE;
  166. }
  167.  
  168. gboolean hovering_over_link = FALSE;
  169. GdkCursor *hand_cursor = NULL;
  170. GdkCursor *regular_cursor = NULL;
  171.  
  172. /* Looks at all tags covering the position (x, y) in the text view, 
  173.  * and if one of them is a link, change the cursor to the "hands" cursor
  174.  * typically used by web browsers.
  175.  */
  176. static void
  177. set_cursor_if_appropriate (GtkTextView    *text_view,
  178.                            gint            x,
  179.                            gint            y)
  180. {
  181.   GSList *tags = NULL, *tagp = NULL;
  182.   GtkTextBuffer *buffer;
  183.   GtkTextIter iter;
  184.   gboolean hovering = FALSE;
  185.  
  186.   buffer = gtk_text_view_get_buffer (text_view);
  187.  
  188.   gtk_text_view_get_iter_at_location (text_view, &iter, x, y);
  189.   
  190.   tags = gtk_text_iter_get_tags (&iter);
  191.   for (tagp = tags;  tagp != NULL;  tagp = tagp->next)
  192.     {
  193.       GtkTextTag *tag = tagp->data;
  194.       gint page = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tag), "page"));
  195.  
  196.       if (page != 0) 
  197.         {
  198.           hovering = TRUE;
  199.           break;
  200.         }
  201.     }
  202.  
  203.   if (hovering != hovering_over_link)
  204.     {
  205.       hovering_over_link = hovering;
  206.  
  207.       if (hovering_over_link)
  208.         gdk_window_set_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), hand_cursor);
  209.       else
  210.         gdk_window_set_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), regular_cursor);
  211.     }
  212.  
  213.   if (tags) 
  214.     g_slist_free (tags);
  215. }
  216.  
  217. /* Update the cursor image if the pointer moved. 
  218.  */
  219. static gboolean
  220. motion_notify_event (GtkWidget      *text_view,
  221.              GdkEventMotion *event)
  222. {
  223.   gint x, y;
  224.  
  225.   gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), 
  226.                                          GTK_TEXT_WINDOW_WIDGET,
  227.                                          event->x, event->y, &x, &y);
  228.  
  229.   set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y);
  230.  
  231.   gdk_window_get_pointer (text_view->window, NULL, NULL, NULL);
  232.   return FALSE;
  233. }
  234.  
  235. /* Also update the cursor image if the window becomes visible
  236.  * (e.g. when a window covering it got iconified).
  237.  */
  238. static gboolean
  239. visibility_notify_event (GtkWidget          *text_view,
  240.              GdkEventVisibility *event)
  241. {
  242.   gint wx, wy, bx, by;
  243.   
  244.   gdk_window_get_pointer (text_view->window, &wx, &wy, NULL);
  245.   
  246.   gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), 
  247.                                          GTK_TEXT_WINDOW_WIDGET,
  248.                                          wx, wy, &bx, &by);
  249.  
  250.   set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), bx, by);
  251.  
  252.   return FALSE;
  253. }
  254.  
  255. GtkWidget *
  256. do_hypertext (GtkWidget *do_widget)
  257. {
  258.   static GtkWidget *window = NULL;
  259.  
  260.   if (!window)
  261.     {
  262.       GtkWidget *view;
  263.       GtkWidget *sw;
  264.       GtkTextBuffer *buffer;
  265.  
  266.       hand_cursor = gdk_cursor_new (GDK_HAND2);
  267.       regular_cursor = gdk_cursor_new (GDK_XTERM);
  268.       
  269.       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  270.       gtk_window_set_screen (GTK_WINDOW (window),
  271.                  gtk_widget_get_screen (do_widget));
  272.       gtk_window_set_default_size (GTK_WINDOW (window),
  273.                    450, 450);
  274.       
  275.       g_signal_connect (window, "destroy",
  276.             G_CALLBACK (gtk_widget_destroyed), &window);
  277.  
  278.       gtk_window_set_title (GTK_WINDOW (window), "Hypertext");
  279.       gtk_container_set_border_width (GTK_CONTAINER (window), 0);
  280.  
  281.       view = gtk_text_view_new ();
  282.       gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), GTK_WRAP_WORD);
  283.       g_signal_connect (view, "key-press-event", 
  284.             G_CALLBACK (key_press_event), NULL);
  285.       g_signal_connect (view, "event-after", 
  286.             G_CALLBACK (event_after), NULL);
  287.       g_signal_connect (view, "motion-notify-event", 
  288.             G_CALLBACK (motion_notify_event), NULL);
  289.       g_signal_connect (view, "visibility-notify-event", 
  290.             G_CALLBACK (visibility_notify_event), NULL);
  291.  
  292.       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
  293.       
  294.       sw = gtk_scrolled_window_new (NULL, NULL);
  295.       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
  296.                       GTK_POLICY_AUTOMATIC,
  297.                       GTK_POLICY_AUTOMATIC);
  298.       gtk_container_add (GTK_CONTAINER (window), sw);
  299.       gtk_container_add (GTK_CONTAINER (sw), view);
  300.  
  301.       show_page (buffer, 1);
  302.  
  303.       gtk_widget_show_all (sw);
  304.     }
  305.  
  306.   if (!GTK_WIDGET_VISIBLE (window))
  307.     {
  308.       gtk_widget_show (window);
  309.     }
  310.   else
  311.     {
  312.       gtk_widget_destroy (window);
  313.       window = NULL;
  314.     }
  315.  
  316.   return window;
  317. }
  318.  
  319.